package net.phoenix.repository;

import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.jcr.Credentials;
import javax.jcr.LoginException;
import javax.jcr.NamespaceRegistry;
import javax.jcr.NoSuchWorkspaceException;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.SimpleCredentials;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
import javax.jcr.nodetype.NodeTypeManager;
import javax.sql.DataSource;

import net.phoenix.repository.dao.JdbcDaoFactory;
import net.phoenix.repository.nodetype.XMLNodeTypeDefinitionManager;
import net.phoenix.repository.value.BasicValueFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Jigsaw server
 * 
 * @author <a href="shamphone@gmail.com">Li XiongFeng</a>
 * @date 2012-1-28
 * @version 1.0.0
 */
public class BasicRepository implements Repository {
	private static final Log log = LogFactory.getLog(BasicRepository.class);
	private String defaultWorkspace;
	private RepositoryDescriptors descriptors;
	private BasicValueFactory valueFactory;
	private NamespaceRegistry namespaces;
	private XMLNodeTypeDefinitionManager nodeTypes;
	private DataSource datasource;
	private JdbcDaoFactory daoFactory;
	private String daoMappingFile;
	private File folder;
	
	public BasicRepository(){
		this.daoMappingFile = "jigsaw-dao-mysql.properties";
		this.defaultWorkspace = "jigsaw";		
	}
	
	
	public BasicRepository(DataSource datasource, File folder){
		this();
		this.datasource = datasource;
		this.folder = folder;
	}
	
	
	public void startup()  throws IOException, RepositoryException{
		if(this.datasource == null)
			throw new IllegalStateException("Datasource should be configured first. ");
		this.namespaces = new BasicNamespaceRegistry();
		this.valueFactory = new BasicValueFactory();
		this.nodeTypes = new XMLNodeTypeDefinitionManager();
		this.nodeTypes.loadFromFolder(folder);
		this.daoFactory = new JdbcDaoFactory();		
		this.daoFactory.loadMappingFromClassPath(daoMappingFile);
		this.descriptors = new RepositoryDescriptors(this.valueFactory);
		log.info("Repository starts successfully!");		
	}
	
	public void setDataSource(DataSource datasource){
		this.datasource = datasource;
	}
	
	public void setNodeTypePath(File path) {
		this.folder = path;
	}

	public ValueFactory getValueFactory() {
		return  this.valueFactory;
	}
	/**
	 * 
	 * @return
	 */
	protected NodeTypeManager getTypeManager() {
		return this.nodeTypes;
	}
	/**
	 * 
	 * @return
	 */
	public JdbcDaoFactory getJdbcDaoFactory() {
		return this.daoFactory;
	}

	/**
	 * 
	 * @return
	 */
	protected NamespaceRegistry createNamespaceRegistry() {
		return this.namespaces;
	}



	@Override
	public String[] getDescriptorKeys() {
		return this.descriptors.getDescriptorKeys();
	}

	@Override
	public boolean isStandardDescriptor(String key) {
		return this.descriptors.isStandardDescriptor(key);
	}

	@Override
	public boolean isSingleValueDescriptor(String key) {
		return this.descriptors.isSingleValueDescriptor(key);
	}

	@Override
	public Value getDescriptorValue(String key) {
		return this.descriptors.getDescriptorValue(key);
	}

	@Override
	public Value[] getDescriptorValues(String key) {
		return this.descriptors.getDescriptorValues(key);
	}

	@Override
	public String getDescriptor(String key) {
		return this.descriptors.getDescriptor(key);
	}

	@Override
	public Session login(Credentials credentials, String workspaceName) throws LoginException, NoSuchWorkspaceException, RepositoryException {
		SimpleCredentials cred = (SimpleCredentials) credentials;
		String username = cred.getUserID();
		String password = new String(cred.getPassword());
		try {
			Connection connection = this.datasource.getConnection(username, password);
			connection.setAutoCommit(false);
			return new BasicSession(this, connection, workspaceName);
		} catch (SQLException e) {
			throw new LoginException(e);
		}
	}

	@Override
	public Session login(Credentials credentials) throws LoginException, RepositoryException {
		return login(credentials, this.defaultWorkspace);
	}

	@Override
	public Session login(String workspaceName) throws LoginException, NoSuchWorkspaceException, RepositoryException {		
		try {
			Connection connection = this.datasource.getConnection();
			connection.setAutoCommit(false);
			return new BasicSession(this, connection, workspaceName);
		} catch (SQLException e) {
			throw new LoginException(e);
		}

	}

	@Override
	public Session login() throws LoginException, RepositoryException {
		return this.login(this.defaultWorkspace);
	}


}
